
#include "mainwindow.h"
#include "mergedialog.h"

MainWindow::MainWindow()
{
    QGridLayout *centralLayout = new QGridLayout();

    imageScene = new ImageScene(this);
    connect(imageScene, SIGNAL(mouseMoved(QGraphicsSceneMouseEvent*)),
            this, SLOT(updateCoordLabel(QGraphicsSceneMouseEvent*)));
    connect(imageScene, SIGNAL(mousePressed(QGraphicsSceneMouseEvent*)),
            this, SLOT(updateInfoDock(QGraphicsSceneMouseEvent*)));
    graphicsView = new QGraphicsView(imageScene, this);
    graphicsView->setMouseTracking(true);
    centralLayout->addWidget(graphicsView, 0, 0);

    vSlider = new QSlider(Qt::Vertical, this);
    hSlider = new QSlider(Qt::Horizontal, this);
    centralLayout->addWidget(vSlider, 0, 1);
    centralLayout->addWidget(hSlider, 1, 0);
    vSlider->hide();
    hSlider->hide();
    vSlider->setTracking(false);
    hSlider->setTracking(false);
    connect(vSlider, SIGNAL(valueChanged(int)), this, SLOT(execIntelResizeHeight(int)));
    connect(hSlider, SIGNAL(valueChanged(int)), this, SLOT(execIntelResizeWidth(int)));

    QWidget *container = new QWidget(this);
    container->setLayout(centralLayout);

    setCentralWidget(container);

    createActions();
    createMenus();
    createStatusBar();
    createDockWidgets();

    execution = normal;
    instructions = new QErrorMessage(this);

    winTitle = "Luvlena";
    setWindowTitle(winTitle);
    setWindowFilePath(QString());
    curFileInfo = new QFileInfo();
    resize(760, 550);

    undoDone=0;
    undoReady=0;
    scissor_flag=false;
}

MainWindow::~MainWindow()
{
    histogramDock->deleteLater();
}

QGraphicsItem* MainWindow::getPixmapItem()
{
    return imagePixmapItem;
}

void MainWindow::newFile()
{
    MainWindow *other = new MainWindow();
    other->show();
    other->setAttribute(Qt::WA_DeleteOnClose);
}

void MainWindow::open()
{
    QStringList formats;
    foreach (QByteArray format, QImageReader::supportedImageFormats())
        if (format.toLower() == format)
            formats.append("*." + format);
    formats.append("*.pnm");

    QString fileName;
    if (pathName.isEmpty())
        fileName = QFileDialog::getOpenFileName(this,
                                    tr("Open Image"),
                                    QDir::homePath(),
                                    tr("Image Files (%1)").arg(formats.join(" ")));
    else
        fileName = QFileDialog::getOpenFileName(this,
                                    tr("Open Image"),
                                    pathName,
                                    tr("Image Files (%1)").arg(formats.join(" ")));
    if (!fileName.isEmpty()) {
        loadFile(fileName);
    }
}

void MainWindow::save()
{
    if (!curFileInfo->isFile())
        saveAs();
    else {
        saveFile(curFileInfo->fileName());
    }
}

void MainWindow::saveAs()
{
    QStringList formats;
    foreach (QByteArray format, QImageWriter::supportedImageFormats())
        if (format.toLower() == format)
            formats.append("*." + format);
    formats.append("*.pnm");
    formats.append("*.pgm");

    QString fileName = QFileDialog::getSaveFileName(this,
                        tr("Choose a file name"),
                        pathName,
                        tr("Image Files (%1)").arg(formats.join(" ")));
    if (fileName.isEmpty())
        return;

    if (saveFile(fileName)) {
        curFileInfo->setFile(fileName);
        pathName = curFileInfo->absolutePath();
        setWindowTitle(curFileInfo->fileName() + " - " + winTitle);
    }
}

void MainWindow::openRecentFile()
{
    QAction *action = qobject_cast<QAction *>(sender());
    if (action) {
        QString filePath = action->data().toString();
        if (QFileInfo(filePath).exists())
            loadFile(filePath);
        else {
            QMessageBox::warning(this, tr("Luvlena"),
                                     tr("Cannot load %1.").arg(filePath));

            //remove from the recent files list!
            QSettings settings("LuvlenaSettings", QSettings::IniFormat);
            QStringList files = settings.value("recentFileList").toStringList();
            files.removeAll(filePath);
            settings.setValue("recentFileList", files);
            foreach (QWidget *widget, QApplication::topLevelWidgets()) {
                MainWindow *mainWin = qobject_cast<MainWindow *>(widget);
                if (mainWin)
                    mainWin->updateRecentFileActions();
            }
        }
    }
}

void MainWindow::closeCur()
{
    undoAct->setEnabled(false);
    redoAct->setEnabled(false);
    undoDone=0;
    undoReady=0;
    switchToMode(normal);

    imageScene->removeItem(imagePixmapItem);
    delete imagePixmapItem;
    imageScene->setSceneRect(QRect());
    histogramDock->clearHistograms();

//    rotate(-rotationAngle);
    graphicsView->resetMatrix();
    rotationAngle = 0;

    updateMenuActions(false);

    normalSize();

    delete curFileInfo;
    curFileInfo = new QFileInfo();

    setWindowTitle(winTitle);
    coordSB->clear();
    statusBar()->showMessage(tr("Closed image"));
}


void MainWindow::cropInit()
{
    if(mode() == cropping)
        return; //already cropping

    switchToMode(cropping);

    graphicsView->setCursor(Qt::OpenHandCursor);

    instructions->showMessage(tr("Adjust the selection box to the size of your choice.<br>"
                                 "To apply the crop, press ENTER. <br>"
                                 "To cancel, press ESCAPE."));

    statusBar()->showMessage(tr("Cropping: Press Enter or Return to apply crop, Escape to cancel"), 0);

    cropSelection = new THGraphicsCropItem(imagePixmapItem, imagePixmapItem->boundingRect());
    graphicsView->centerOn(cropSelection->cropRect().center());
}

void MainWindow::resizeSwitch(QSize size, int filter)
{
    QApplication::setOverrideCursor(Qt::WaitCursor);
    setUndo();
    QString fType;
    switch(filter)
    {
    case AVERAGE:
        image = image.resizeAverage(size.width(), size.height());
        fType = tr("Average");
        break;
    case BILINEAR:
        image = image.resizeBilinear(size.width(), size.height());
        fType = tr("Bilinear");
        break;
    }

    QApplication::restoreOverrideCursor();

    statusBar()->showMessage(tr("Resized image %1 - New size: %2x%3 - %4 filter").arg(curFileInfo->fileName())
                             .arg(size.width())
                             .arg(size.height())
                             .arg(fType));

    setMode(normal);
    updateDisplay();
}

void MainWindow::setMerge(LImage other, double coef)
{
    m_other = other;
    m_coef = coef;
}

// Vertical resizing means processing Horizontal seams
void MainWindow::intelResizeHeight()
{
    switchToMode(intelResizeH);

    bool ok;
    int preProcNum = QInputDialog::getInt(this,
                                           tr("Height Content-Aware Resizing"),
                                           tr("Set the number of seams to preprocess."
                                              "<br>(max rows to add/remove)"),
                                           10,    //default
                                           1,      //minimum
                                           1000,   //maximum
                                           1,      //step
                                           &ok);
    if(ok) {
        QApplication::setOverrideCursor(Qt::WaitCursor);
        QProgressDialog progress(this);
        progress.setLabelText("Seam preprocessing...");
        progress.setMaximum(preProcNum);
        progress.setWindowTitle(tr("Preprocessing"));
        progress.setModal(true);

        QImage img(image.getImage());
        caresizeH = new Caresize(image.getImage().convertToFormat(QImage::Format_RGB32,img.colorTable()));

        caresizeH->horizontalInit();

        for (int i=0; i < preProcNum; i++) {
            caresizeH->horizontalProcessN(1);
            caresizeH->horizontalAddN(1);
            progress.setValue(i);

            if(progress.wasCanceled()) {
                switchToMode(normal);
                QApplication::restoreOverrideCursor();
                return;
            }
        }
        vSlider->setMaximum(caresizeH->maxResizeH());
        vSlider->setMinimum(caresizeH->minResizeH());
        vSlider->setSliderPosition(img.height());
        vSlider->show();
        QApplication::restoreOverrideCursor();

        statusBar()->showMessage(tr("Resizing: Drag the slider to change the size of the image."), 0);
    }
    else {
        setMode(normal); //User pressed Cancel
    }
}

void MainWindow::execIntelResizeHeight(int value)
{
    if(vSlider->isVisible()) {
    setUndo();
    image = LImage(caresizeH->resizeImageH(value));
    updateDisplay();
    }
}

void MainWindow::intelResizeWidth()
{
    switchToMode(intelResizeW);

    bool ok;
    int preProcNum = QInputDialog::getInt(this,
                                           tr("Width Content-Aware Resizing"),
                                           tr("Set the number of seams to preprocess."
                                              "<br>(max columns to add/remove)"),
                                           10,    //default
                                           1,      //minimum
                                           1000,   //maximum
                                           1,      //step
                                           &ok);
    if(ok) {
        QApplication::setOverrideCursor(Qt::WaitCursor);
        QProgressDialog progress(this);
        progress.setLabelText(tr("Seam preprocessing..."));
        progress.setMaximum(preProcNum);
        progress.setWindowTitle("Preprocessing");
        progress.setModal(true);

        QImage img(image.getImage());
        caresizeV = new Caresize(image.getImage().convertToFormat(QImage::Format_RGB32,img.colorTable()));

        caresizeV->verticalInit();

        for (int i=0; i < preProcNum; i++) {
            caresizeV->verticalProcessN(1);
            caresizeV->verticalAddN(1);
            progress.setValue(i);

            if(progress.wasCanceled()) {
                switchToMode(normal);
                QApplication::restoreOverrideCursor();
                return;
            }
        }
        hSlider->setMaximum(caresizeV->maxResizeV());
        hSlider->setMinimum(caresizeV->minResizeV());
        hSlider->setSliderPosition(img.width());
        hSlider->show();
        QApplication::restoreOverrideCursor();

        statusBar()->showMessage(tr("Resizing: Drag the slider to change the size of the image."), 0);
    }
    else {
        setMode(normal); //User pressed Cancel
    }
}

void MainWindow::execIntelResizeWidth(int value)
{
    if(hSlider->isVisible()) {
    setUndo();
        image = LImage(caresizeV->resizeImageV(value));
        updateDisplay();
    }
}

void MainWindow::scissorsInit()
{
    switchToMode(scissors);
    statusBar()->showMessage(tr("Intelligent scissors mode: select two points. Press Enter to Accept, Press Esc to Quit"));
}

void MainWindow::rotateCW()
{
    rotate(90);
    statusBar()->showMessage(QString("Rotated Clockwise"), 2000);
}

void MainWindow::rotateCCW()
{
    rotate(-90);
    statusBar()->showMessage(QString("Rotated Counter-Clockwise"), 2000);
}

void MainWindow::zoomIn()
{
    scaleView(1.25);
}

void MainWindow::zoomOut()
{
    scaleView(0.75);
}

void MainWindow::normalSize()
{
    QRectF unit = graphicsView->matrix().mapRect(QRectF(0, 0, 1, 1));
    graphicsView->scale(1 / unit.width(), 1 / unit.height());
    zoomLevel = 100;
    updateZoomLabel();
}

void MainWindow::fitInWindow()
{
    //known bug of remaining space:
    //http://bugreports.qt.nokia.com/browse/QTBUG-1047?page=com.atlassian.jira.plugin.system.issuetabpanels%3Aall-tabpanel
    QRectF unity = graphicsView->matrix().mapRect(QRectF(0, 0, 1, 1));
    graphicsView->scale(1/unity.width(), 1/unity.height());
    QRectF viewRect = graphicsView->viewport()->rect().adjusted(2, 2, -2, -2);
    QRectF sceneRect = graphicsView->matrix().mapRect(imagePixmapItem->sceneBoundingRect());
    qreal xratio = viewRect.width()/sceneRect.width();
    qreal yratio = viewRect.height()/sceneRect.height();
    qreal finalRatio = qMin(xratio, yratio);
    graphicsView->scale(finalRatio, finalRatio);
    graphicsView->centerOn(imagePixmapItem->sceneBoundingRect().center());

    zoomLevel = finalRatio * 100;
    updateZoomLabel();
}

void MainWindow::fillWindow()
{
    QRectF unity = graphicsView->matrix().mapRect(QRectF(0, 0, 1, 1));
    graphicsView->scale(1/unity.width(), 1/unity.height());
    QRectF viewRect = graphicsView->viewport()->rect().adjusted(2, 2, -2, -2);
    QRectF sceneRect = graphicsView->matrix().mapRect(imagePixmapItem->sceneBoundingRect());
    qreal xratio = viewRect.width()/sceneRect.width();
    qreal yratio = viewRect.height()/sceneRect.height();
    qreal finalRatio = qMax(xratio, yratio);
    graphicsView->scale(finalRatio, finalRatio);
    graphicsView->centerOn(imagePixmapItem->sceneBoundingRect().center());

    zoomLevel = finalRatio * 100;
    updateZoomLabel();
}

void MainWindow::blur()
{
    setUndo();
    Filter *filter=new Blur();
    QImage temp=image.getImage();
    QApplication::setOverrideCursor(Qt::WaitCursor);
    image=LImage(filter->convolve(&temp));
    updateDisplay();
    QApplication::restoreOverrideCursor();
    delete filter;
}

void MainWindow::gaussBlur()
{
    setUndo();
    Filter *filter=new GaussianBlur();
    QImage temp=image.getImage();
    image=LImage(filter->convolve(&temp));
    // call Arun's function and get resulting image
    updateDisplay();
    delete filter;
}

void MainWindow::sharpen()
{
    setUndo();
    bool ok;
    double coef = QInputDialog::getDouble(this,
                                           tr("Sharpen"),
                                           tr("Set the sharpening coefficient"),
                                           0.10,    //default
                                           0.00,      //minimum
                                           2.00,   //maximum
                                           2,      //decimals
                                           &ok);
    if(ok) {
        Filter *filter=new Sharpen(coef);
        QImage temp=image.getImage();
        QApplication::setOverrideCursor(Qt::WaitCursor);
        image=LImage(filter->convolve(&temp));
        updateDisplay();
        QApplication::restoreOverrideCursor();
        delete filter;
    }
}

void MainWindow::edgeDetect()
{
    setUndo();
    Filter *filter=new EdgeDetection();
    QImage temp=image.getImage();
    QApplication::setOverrideCursor(Qt::WaitCursor);
    image=LImage(filter->convolve(&temp));
    updateDisplay();
    QApplication::restoreOverrideCursor();
    delete filter;
}
void MainWindow::sobel()
{
    setUndo();
    Filter *filter=new SobelFilter();
    QImage temp=image.getImage();
    QApplication::setOverrideCursor(Qt::WaitCursor);
    image=LImage(filter->convolve(&temp));
    updateDisplay();
    QApplication::restoreOverrideCursor();
    delete filter;
}

void MainWindow::emboss()
{
    setUndo();
    Filter *filter=new Emboss();
    QImage temp=image.getImage();
    QApplication::setOverrideCursor(Qt::WaitCursor);
    image=LImage(filter->convolve(&temp));
    updateDisplay();
    QApplication::restoreOverrideCursor();
    delete filter;
}

void MainWindow::blurFFT()
{
    setUndo();
    bool ok;
    int size = QInputDialog::getInt(this,
                                           tr("FFT Blur"),
                                           tr("Set the size of the mask."),
                                           10,    //default
                                           3,      //minimum
                                           1000,   //maximum
                                           1,      //step
                                           &ok);
    if(ok) {
        Filter *filter=new Blur(size, size);
        QImage temp=image.getImage();
        QApplication::setOverrideCursor(Qt::WaitCursor);
        image=LImage(filter->convolveFFT(&temp));
        updateDisplay();
        QApplication::restoreOverrideCursor();
        delete filter;
    }
}

void MainWindow::gaussBlurFFT()
{
    setUndo();
    Filter *filter=new GaussianBlur();
    QImage temp=image.getImage();
    QApplication::setOverrideCursor(Qt::WaitCursor);
    image=LImage(filter->convolveFFT(&temp));
    updateDisplay();
    QApplication::restoreOverrideCursor();
    delete filter;
}

void MainWindow::sharpenFFT()
{
    setUndo();
    bool ok;
    double coef = QInputDialog::getDouble(this,
                                           tr("Sharpen"),
                                           tr("Set the sharpening coefficient"),
                                           0.10,    //default
                                           0.00,      //minimum
                                           2.00,   //maximum
                                           2,      //decimals
                                           &ok);
    if(ok) {
        Filter *filter=new Sharpen(coef);
        QImage temp=image.getImage();
        QApplication::setOverrideCursor(Qt::WaitCursor);
        image=LImage(filter->convolveFFT(&temp));
        updateDisplay();
        QApplication::restoreOverrideCursor();
        delete filter;
    }
}

void MainWindow::edgeDetectFFT()
{
    setUndo();
    Filter *filter=new EdgeDetection();
    QImage temp=image.getImage();
    QApplication::setOverrideCursor(Qt::WaitCursor);
    image=LImage(filter->convolveFFT(&temp));
    updateDisplay();
    QApplication::restoreOverrideCursor();
    delete filter;
}
void MainWindow::sobelFFT()
{
    setUndo();
    Filter *filter=new SobelFilter();
    QImage temp=image.getImage();
    QApplication::setOverrideCursor(Qt::WaitCursor);
    image=LImage(filter->convolveFFT(&temp));
    updateDisplay();
    QApplication::restoreOverrideCursor();
    delete filter;
}

void MainWindow::embossFFT()
{
    setUndo();
    Filter *filter=new Emboss();
    QImage temp=image.getImage();
    QApplication::setOverrideCursor(Qt::WaitCursor);
    image=LImage(filter->convolveFFT(&temp));
    updateDisplay();
    QApplication::restoreOverrideCursor();
    delete filter;
}
void MainWindow::toNegative()
{
    setUndo();
    QApplication::setOverrideCursor(Qt::WaitCursor);
    image=image.convertToNegative();
    updateDisplay();
    QApplication::restoreOverrideCursor();
}

void MainWindow::histogramStretch()
{
    setUndo();
    QApplication::setOverrideCursor(Qt::WaitCursor);
    image=image.histogramStretching();
    updateDisplay();
    QApplication::restoreOverrideCursor();
}

void MainWindow::histogramHSIStretch()
{
    setUndo();
    QApplication::setOverrideCursor(Qt::WaitCursor);
    image=image.colorHSIHistogramStretching();
    updateDisplay();
    QApplication::restoreOverrideCursor();
}

void MainWindow::histogramEqu()
{
    setUndo();
    QApplication::setOverrideCursor(Qt::WaitCursor);
    image=image.histogramEqualization();
    updateDisplay();
    QApplication::restoreOverrideCursor();
}

void MainWindow::histogramHSIEqu()
{
    setUndo();
    QApplication::setOverrideCursor(Qt::WaitCursor);
    image=image.HSIHistogramEqualization();
    updateDisplay();
    QApplication::restoreOverrideCursor();
}

void MainWindow::toGrayscale()
{
    setUndo();
    QApplication::setOverrideCursor(Qt::WaitCursor);
    image=image.convertToGrayScale();
    updateDisplay();
    QApplication::restoreOverrideCursor();
}

void MainWindow::customConvolutionInit()
{
    CustomConvolutionDialog *diag = new CustomConvolutionDialog(this);
    connect(diag, SIGNAL(matrixAccepted(double*, int, int)),
            this, SLOT(customConvolution(double*,int,int)));
    diag->exec();
}

void MainWindow::customConvolution(double *matrix, int width, int height)
{

    setUndo();
    Filter *filter=new Filter();
    filter->setKernel(matrix, width, height);
    QImage temp=image.getImage();
    QApplication::setOverrideCursor(Qt::WaitCursor);
    image=LImage(filter->convolve(&temp));
    updateDisplay();
    QApplication::restoreOverrideCursor();
    delete filter;
}

void MainWindow::setUndo(){
    undoReady=1;
    undoimage=image;
    undoDone=0;
}

void MainWindow::undo(){
    if(undoDone==0 && undoReady==1)
    {
        undoDone=1;
        redoimage=image;
        image=undoimage;
        updateDisplay();
    }
}

void MainWindow::redo(){
    if(undoDone==1)
    {
        undoDone=0;
        image=redoimage;
        updateDisplay();
    }
}

void MainWindow::about()
{
    QString text = "<p>" + tr("The <b>Luvlena Image Editor</b> is a student project "
                      "for the Mosig Masters course at Grenoble universities.") + "</p>";
    text += "<p>" "The students involved in this project are : " "</p>"
            "<center >Amr Najjar <br>"
            "Arun Shivanandan <br>"
            "Daniel R&iacute;os Pav&iacute;a <br>"
            "Thomas Vincent-Sweet </center>";
    QMessageBox::about(this, tr("About Luvlena Image Editor"), text);
}

void MainWindow::showResizeDialog()
{
    switchToMode(resizing);

    ResizeDialog *diag = new ResizeDialog(this, imagePixmapItem->pixmap().size());
    diag->setModal(true);

    connect(diag, SIGNAL(resizeImage(QSize,int)), this, SLOT(resizeSwitch(QSize, int)));

    diag->exec();
}

void MainWindow::showMergeDialog()
{
    switchToMode(mergeDiag);

    MergeDialog *diag = new MergeDialog(this);
    diag->setModal(true);

    connect(diag, SIGNAL(merge(LImage,double)), this, SLOT(setMerge(LImage,double)));

    if (diag->exec()) {
        setMode(merging);
        mergeItem = new THGraphicsMergeItem(imagePixmapItem, m_other.getPixmap().rect());
        graphicsView->centerOn(mergeItem->cropRect().center());
    }
}

void MainWindow::updateCoordLabel(QGraphicsSceneMouseEvent *event)
{
    QPointF posS = event->scenePos();
    QGraphicsPixmapItem *item = (QGraphicsPixmapItem*)imageScene->itemAt(posS);
    if(item) {
        posS = item->mapFromScene(posS);
        int x = posS.toPoint().x();
        int y = posS.toPoint().y();
        coordSB->setText(tr("%1, %2")
                         .arg(x).arg(y));
        coordSB->setForegroundRole(QPalette::WindowText);
        if(event->buttons() == Qt::LeftButton
           || event->buttons() == Qt::RightButton) {
            updateInfoDock(event);
        }
    }
    else if(imageScene->items().size() > 0){
        coordSB->setText(tr("%1, %2")
                         .arg(posS.toPoint().x())
                         .arg(posS.toPoint().y()));
        coordSB->setForegroundRole(QPalette::Mid);
    }
}

void MainWindow::updateInfoDock(QGraphicsSceneMouseEvent *event)
{
    QPointF posS = event->scenePos();
    QGraphicsPixmapItem *item = qgraphicsitem_cast<QGraphicsPixmapItem*>(imageScene->itemAt(posS));
    if(item) {
        posS = item->mapFromScene(posS);
        int pos_x = posS.toPoint().x();
        int pos_y = posS.toPoint().y();
        xl->setText(tr("%1").arg(pos_x));
        yl->setText(tr("%1").arg(pos_y));
        QRgb rgb = item->pixmap().toImage().pixel(pos_x, pos_y);
        int r = qRed(rgb);
        int g = qGreen(rgb);
        int b = qBlue(rgb);
        lR->setText(tr("%1").arg(r));
        lG->setText(tr("%1").arg(g));
        lB->setText(tr("%1").arg(b));
        int y=( (  66 * r + 129 * g +  25 * b + 128) >> 8) +  16;
        int u=( ( -38 * r -  74 * g + 112 * b + 128) >> 8) + 128;
        int v=( ( 112 * r -  94 * g -  18 * b + 128) >> 8) + 128;
        lY->setText(tr("%1").arg(y));
        lU->setText(tr("%1").arg(u));
        lV->setText(tr("%1").arg(v));
    }
    switch(mode())
    {
    case scissors:
        if (item) {
            if (scissor_flag==false){
                QImage img=image.getImage();
                intelligent = new IntelligentResizeUtility(&img);
                x1_scissor=posS.toPoint().x();
                y1_scissor=posS.toPoint().y();
                scissor_flag=true;
                return;
            }
            int x2=posS.toPoint().x();
            int y2=posS.toPoint().y();
            m_other=LImage(image.getImage());
            LImage intellignetScissorImage=LImage(this->image);
            QLinkedList<QPoint>* path;
            QLinkedList<QPoint> trap;
            path=&trap;
            QApplication::setOverrideCursor(Qt::WaitCursor);
            intelligent->tracePath(intelligent->retrivePixel(x1_scissor,y1_scissor),
                                   intelligent->retrivePixel(x2,y2),path);
             //double tmp_cost=0.0;
            foreach (QPoint qp,*path)
            {

                IntelligentResizeUtility::pixelsGrid[qp.x()+qp.y()*IntelligentResizeUtility::width].setContour(true);
                intellignetScissorImage.setPixel(qp.x(),qp.y(),0,255,0);
                intellignetScissorImage.setPixel(qp.x()+1,qp.y()-1,0,255,0);
                intellignetScissorImage.setPixel(qp.x()-1,qp.y()+1,0,255,0);
                intellignetScissorImage.setPixel(qp.x()+1,qp.y()+1,0,255,0);
                intellignetScissorImage.setPixel(qp.x()+1,qp.y()+1,0,255,0);
            }
            image=intellignetScissorImage;
            updateDisplay();
            x1_scissor=x2;
            y1_scissor=y2;
            cout<<scissor_flag<<endl;
            path->clear();
            QApplication::restoreOverrideCursor();
            }
        break;
        default:
        break;
    }
}

void MainWindow::keyPressEvent(QKeyEvent *event)
{
    switch(event->key())
    {
    case Qt::Key_Return:
    case Qt::Key_Enter:
        if (mode() == cropping) {
            //call cropping func
            applyCrop(cropSelection->cropRect());
            delete cropSelection;
            setMode(normal);
            QApplication::restoreOverrideCursor();
            graphicsView->setCursor(Qt::ArrowCursor);
            fitInWindow();
        }
        else if (mode() == merging) {
            //call merging func
            applyMerge(mergeItem->cropRect());
            delete mergeItem;
            setMode(normal);
            QApplication::restoreOverrideCursor();
            graphicsView->setCursor(Qt::ArrowCursor);
        }
        else if (mode() == intelResizeH || mode() == intelResizeW) {
            statusBar()->showMessage(tr("Accepted Content-Aware Resize"), 2000);
            setMode(normal);
        }
        else if (mode() == scissors) {
            statusBar()->showMessage(tr("Accepted Intelligent scissors selection"), 2000);
            QImage qimage=QImage(image.getImage().width(),image.getImage().height(),image.getImage().format());
            intelligent->cutContour(&qimage);
            setUndo();
            image=qimage;
            intelligent->~IntelligentResizeUtility();
            this->scissor_flag=false;
            updateDisplay();
            setMode(normal);
        }
        break;
    case Qt::Key_Escape:
    case Qt::Key_Backspace:
        switchToMode(normal);
    default:
        QMainWindow::keyPressEvent(event);
    }
}

void MainWindow::setMode(Mode mode)
{
    execution = mode;
}

void MainWindow::cancelCurMode()
{
    switch(this->mode()) {
    case cropping:
        statusBar()->showMessage(tr("Cancelled Crop"), 2000);
        delete cropSelection;
        QApplication::restoreOverrideCursor();
        graphicsView->setCursor(Qt::ArrowCursor);
        break;
    case merging:
        delete mergeItem;
    case mergeDiag:
        statusBar()->showMessage(tr("Cancelled Merge"), 2000);
        QApplication::restoreOverrideCursor();
        graphicsView->setCursor(Qt::ArrowCursor);
        break;
    case scissors:
        statusBar()->showMessage(tr("Cancelled Intelligent scissors selection"), 2000);
        delete intelligent;
        this->scissor_flag=false;
        image=LImage(m_other.getImage());
        updateDisplay();
        break;
    case intelResizeH:
        vSlider->hide();
        delete caresizeH;
        break;
    case intelResizeW:
        hSlider->hide();
        delete caresizeV;
        break;
    case resizing:
    case normal:
        //nothing to do...
        break;
    }
    setMode(normal);
}

void MainWindow::switchToMode(Mode mode)
{
    cancelCurMode();
    setMode(mode);
}

MainWindow::Mode MainWindow::mode()
{
    return execution;
}

void MainWindow::createActions()
{
    newAct = new QAction(tr("&New"), this);
    newAct->setShortcut(tr("Ctrl+N"));
    newAct->setStatusTip(tr("Create a new window"));
    connect(newAct, SIGNAL(triggered()), this, SLOT(newFile()));

    openAct = new QAction(tr("&Open..."), this);
    openAct->setShortcut(tr("Ctrl+O"));
    openAct->setStatusTip(tr("Open an existing file"));
    connect(openAct, SIGNAL(triggered()), this, SLOT(open()));

    for (int i = 0; i < MaxRecentFiles; ++i) {
        recentFileActs[i] = new QAction(this);
        recentFileActs[i]->setVisible(false);
        recentFileActs[i]->setShortcut(tr("Ctrl+%1").arg(i+1));
        connect(recentFileActs[i], SIGNAL(triggered()),
                this, SLOT(openRecentFile()));
    }

    saveAct = new QAction(tr("&Save"), this);
    saveAct->setShortcut(tr("Ctrl+S"));
    saveAct->setEnabled(false);
    saveAct->setStatusTip(tr("Save the image to disk"));
    connect(saveAct, SIGNAL(triggered()), this, SLOT(save()));

    saveAsAct = new QAction(tr("&Save &as..."), this);
    saveAsAct->setShortcut(tr("Ctrl+Shift+S"));
    saveAsAct->setEnabled(false);
    saveAsAct->setStatusTip(tr("Save the image under a new name"));
    connect(saveAsAct, SIGNAL(triggered()), this, SLOT(saveAs()));

    closeAct = new QAction(tr("&Close image"), this);
    closeAct->setShortcut(tr("Ctrl+W"));
    closeAct->setStatusTip(tr("Close the image"));
    closeAct->setEnabled(false);
    connect(closeAct, SIGNAL(triggered()), this, SLOT(closeCur()));

    closeWinAct = new QAction(tr("&Close window"), this);
    closeWinAct->setShortcut(tr("Ctrl+Shift+W"));
    closeWinAct->setStatusTip(tr("Close this window"));
    connect(closeWinAct, SIGNAL(triggered()), this, SLOT(close()));

    quitAct = new QAction(tr("&Quit"), this);
    quitAct->setShortcut(tr("Ctrl+Q"));
    quitAct->setStatusTip(tr("Quit the application (closes all open windows)"));
    connect(quitAct, SIGNAL(triggered()), qApp, SLOT(closeAllWindows()));

    undoAct = new QAction(tr("&Undo"), this);
    undoAct->setShortcut(tr("Ctrl+Z"));
    undoAct->setEnabled(false);
    connect(undoAct, SIGNAL(triggered()), this, SLOT(undo()));

    redoAct = new QAction(tr("&Redo"), this);
    redoAct->setShortcut(tr("Ctrl+Shift+Z"));
    redoAct->setEnabled(false);
    connect(redoAct, SIGNAL(triggered()), this, SLOT(redo()));

    cropAct = new QAction(tr("&Crop"), this);
    cropAct->setShortcut(tr("Ctrl+Shift+C"));
    cropAct->setStatusTip(tr("Crop the image"));
    cropAct->setEnabled(false);
    connect(cropAct, SIGNAL(triggered()), this, SLOT(cropInit()));

    resizeAct = new QAction(tr("Re&size"), this);
    resizeAct->setShortcut(tr("Ctrl+R"));
    resizeAct->setStatusTip(tr("Resize the image"));
    resizeAct->setEnabled(false);
    connect(resizeAct, SIGNAL(triggered()), this, SLOT(showResizeDialog()));

    mergeAct = new QAction(tr("&Merge"), this);
    mergeAct->setShortcut(tr("Ctrl+M"));
    mergeAct->setStatusTip(tr("Merge this image with another"));
    mergeAct->setEnabled(false);
    connect(mergeAct, SIGNAL(triggered()), this, SLOT(showMergeDialog()));

    intelligentResizeVAct = new QAction(tr("Height Content-Aware Resize"), this);
    intelligentResizeVAct->setStatusTip(tr("Content-aware height resizing of the picture"));
    intelligentResizeVAct->setEnabled(false);
    connect(intelligentResizeVAct, SIGNAL(triggered()), this, SLOT(intelResizeHeight()));

    intelligentResizeHAct = new QAction(tr("Width Content-Aware Resize"), this);
    intelligentResizeHAct->setStatusTip(tr("Content-aware width resizing of the picture"));
    intelligentResizeHAct->setEnabled(false);
    connect(intelligentResizeHAct, SIGNAL(triggered()), this, SLOT(intelResizeWidth()));

    intelligentScissorsAct = new QAction(tr("&Intelligent Scissors"), this);
    intelligentScissorsAct->setShortcut(tr("Ctrl+K"));
    intelligentScissorsAct->setStatusTip(tr("Make a selection using intelligent edge detection"));
    intelligentScissorsAct->setEnabled(false);
    connect(intelligentScissorsAct, SIGNAL(triggered()), this, SLOT(scissorsInit()));

    rotateCAct = new QAction(tr("R&otate clockwise"), this);
    rotateCAct->setShortcut(tr("Ctrl+Right"));
    rotateCAct->setStatusTip(tr("Rotate the image 90 degrees to the right"));
    rotateCAct->setEnabled(false);
    connect(rotateCAct, SIGNAL(triggered()), this, SLOT(rotateCW()));

    rotateACAct = new QAction(tr("Rotate &anti-clockwise"), this);
    rotateACAct->setShortcut(tr("Ctrl+Left"));
    rotateACAct->setStatusTip(tr("Rotate the image 90 degrees to the left"));
    rotateACAct->setEnabled(false);
    connect(rotateACAct, SIGNAL(triggered()), this, SLOT(rotateCCW()));

    zoomInAct = new QAction(tr("Zoom &In (25%)"), this);
    zoomInAct->setShortcut(tr("+"));
    zoomInAct->setStatusTip(tr("Enlarge the image"));
    zoomInAct->setEnabled(false);
    connect(zoomInAct, SIGNAL(triggered()), this, SLOT(zoomIn()));

    zoomOutAct = new QAction(tr("Zoom &Out (25%)"), this);
    zoomOutAct->setShortcut(tr("-"));
    zoomOutAct->setStatusTip(tr("Shrink the image"));
    zoomOutAct->setEnabled(false);
    connect(zoomOutAct, SIGNAL(triggered()), this, SLOT(zoomOut()));

    normalSizeAct = new QAction(tr("&Normal Size"), this);
    normalSizeAct->setShortcut(tr("1"));
    normalSizeAct->setStatusTip(tr("Show the image at its normal size"));
    normalSizeAct->setEnabled(false);
    connect(normalSizeAct, SIGNAL(triggered()), this, SLOT(normalSize()));

    fitInWindowAct = new QAction(tr("&Fit in Window"), this);
    fitInWindowAct->setShortcut(tr("Ctrl+F"));
    fitInWindowAct->setStatusTip(tr("Adjust the zoom ratio so that the image becomes fully visible"));
    fitInWindowAct->setEnabled(false);
    connect(fitInWindowAct, SIGNAL(triggered()), this, SLOT(fitInWindow()));

    fillWindowAct = new QAction(tr("Fill &Window"), this);
    fillWindowAct->setShortcut(tr("Ctrl+Shift+F"));
    fillWindowAct->setStatusTip(tr("Adjust the zoom ratio so that the image fills the window"));
    fillWindowAct->setEnabled(false);
    connect(fillWindowAct, SIGNAL(triggered()), this, SLOT(fillWindow()));

    blurAct = new QAction(tr("&Blur"), this);
    blurAct->setEnabled(false);
    connect(blurAct, SIGNAL(triggered()), this, SLOT(blur()));

    gaussBlurAct = new QAction(tr("&Gaussian Blur"), this);
    gaussBlurAct->setEnabled(false);
    connect(gaussBlurAct, SIGNAL(triggered()), this, SLOT(gaussBlur()));

    sharpenAct = new QAction(tr("&Sharpen"), this);
    sharpenAct->setEnabled(false);
    connect(sharpenAct, SIGNAL(triggered()), this, SLOT(sharpen()));

    edgeDetectAct = new QAction(tr("&Laplacian"), this);
    edgeDetectAct->setEnabled(false);
    connect(edgeDetectAct, SIGNAL(triggered()), this, SLOT(edgeDetect()));

    sobelAct = new QAction(tr("&Sobel"), this);
    sobelAct->setEnabled(false);
    connect(sobelAct, SIGNAL(triggered()), this, SLOT(sobel()));

    embossAct = new QAction(tr("&Emboss Edges"), this);
    embossAct->setEnabled(false);
    connect(embossAct, SIGNAL(triggered()), this, SLOT(emboss()));

    blurFFTAct = new QAction(tr("&Blur"), this);
    blurFFTAct->setEnabled(false);
    connect(blurFFTAct, SIGNAL(triggered()), this, SLOT(blurFFT()));

    gaussBlurFFTAct = new QAction(tr("&Gaussian Blur"), this);
    gaussBlurFFTAct->setEnabled(false);
    connect(gaussBlurFFTAct, SIGNAL(triggered()), this, SLOT(gaussBlurFFT()));

    sharpenFFTAct = new QAction(tr("&Sharpen"), this);
    sharpenFFTAct->setEnabled(false);
    connect(sharpenFFTAct, SIGNAL(triggered()), this, SLOT(sharpenFFT()));

    edgeDetectFFTAct = new QAction(tr("&Laplacian"), this);
    edgeDetectFFTAct->setEnabled(false);
    connect(edgeDetectFFTAct, SIGNAL(triggered()), this, SLOT(edgeDetectFFT()));

    sobelFFTAct = new QAction(tr("&Sobel"), this);
    sobelFFTAct->setEnabled(false);
    connect(sobelFFTAct, SIGNAL(triggered()), this, SLOT(sobelFFT()));

    embossFFTAct = new QAction(tr("&Emboss"), this);
    embossFFTAct->setEnabled(false);
    connect(embossFFTAct, SIGNAL(triggered()), this, SLOT(embossFFT()));

    negativeAct=new QAction(tr("&Convert Negative"), this);
    negativeAct->setEnabled(false);
    connect(negativeAct, SIGNAL(triggered()), this, SLOT(toNegative()));

    histogramStretchAct=new QAction(tr("&Stretch Histogram"), this);
    histogramStretchAct->setEnabled(false);
    connect(histogramStretchAct, SIGNAL(triggered()), this, SLOT(histogramStretch()));

    histogramHSIStretchAct=new QAction(tr("&HSI Stretch Histogram"), this);
    histogramHSIStretchAct->setEnabled(false);
    connect(histogramHSIStretchAct, SIGNAL(triggered()), this, SLOT(histogramHSIStretch()));

    histogramEquAct=new QAction(tr("&Equalize Histogram"), this);
    histogramEquAct->setEnabled(false);
    connect(histogramEquAct, SIGNAL(triggered()), this, SLOT(histogramEqu()));

    histogramHSIEquAct=new QAction(tr("&HSI Equalize Histogram"), this);
    histogramHSIEquAct->setEnabled(false);
    connect(histogramHSIEquAct, SIGNAL(triggered()), this, SLOT(histogramHSIEqu()));

    toGrayscaleAct=new QAction(tr("&Convert Grayscale"), this);
    toGrayscaleAct->setEnabled(false);
    connect(toGrayscaleAct, SIGNAL(triggered()), this, SLOT(toGrayscale()));

    customConvolutionAct = new QAction(tr("&Custom Convolution"), this);
    customConvolutionAct->setEnabled(false);
    connect(customConvolutionAct, SIGNAL(triggered()), this, SLOT(customConvolutionInit()));

    aboutAct = new QAction(tr("&About"), this);
    aboutAct->setStatusTip(tr("Show the application's About box"));
    connect(aboutAct, SIGNAL(triggered()), this, SLOT(about()));

    aboutQtAct = new QAction(tr("About &Qt"), this);
    aboutQtAct->setStatusTip(tr("Show the Qt library's About box"));
    connect(aboutQtAct, SIGNAL(triggered()), qApp, SLOT(aboutQt()));
}

void MainWindow::createMenus()
{
    fileMenu = new QMenu(tr("&File"), this);
    fileMenu->addAction(newAct);
    fileMenu->addAction(openAct);

    recentFilesMenu = new QMenu(tr("&Recent Files"), this);
    for (int i = 0; i < MaxRecentFiles; ++i)
        recentFilesMenu->addAction(recentFileActs[i]);
    fileMenu->addMenu(recentFilesMenu);

    fileMenu->addSeparator();
    fileMenu->addAction(saveAct);
    fileMenu->addAction(saveAsAct);
    fileMenu->addSeparator();
    fileMenu->addAction(closeAct);
    fileMenu->addAction(closeWinAct);
    fileMenu->addSeparator();
    fileMenu->addAction(quitAct);
    updateRecentFileActions();

    editMenu = new QMenu(tr("&Edit"), this);
    editMenu->setToolTip(tr("Edit the image"));
    editMenu->addAction(undoAct);
    editMenu->addAction(redoAct);
    editMenu->addSeparator();
    editMenu->addAction(cropAct);
    editMenu->addAction(resizeAct);
    editMenu->addAction(mergeAct);
    editMenu->addAction(intelligentResizeVAct);
    editMenu->addAction(intelligentResizeHAct);
    editMenu->addAction(intelligentScissorsAct);
    editMenu->addAction(rotateCAct);
    editMenu->addAction(rotateACAct);

    viewMenu = new QMenu(tr("&View"), this);
    viewMenu->setToolTip(tr("Change the view"));

    zoomMenu = new QMenu(tr("&Zoom"), this);
    zoomMenu->addAction(zoomInAct);
    zoomMenu->addAction(zoomOutAct);
    zoomMenu->addAction(normalSizeAct);
    zoomMenu->addAction(fitInWindowAct);
    zoomMenu->addAction(fillWindowAct);
    viewMenu->addMenu(zoomMenu);
    viewMenu->addSeparator();

    blurMenu = new QMenu(tr("&Blur"), this);
    blurMenu->addAction(blurAct);
    blurMenu->addAction(gaussBlurAct);

    sharpenMenu = new QMenu(tr("&Sharpen"), this);
    sharpenMenu->addAction(sharpenAct);

    edgeDetectMenu = new QMenu(tr("&Detect Edges"), this);
    edgeDetectMenu->addAction(sobelAct);
    //edgeDetectMenu->addAction(edgeDetectCAct);
    edgeDetectMenu->addAction(edgeDetectAct);
    edgeDetectMenu->addAction(embossAct);

    blurFFTMenu = new QMenu(tr("&Blur"), this);
    blurFFTMenu->addAction(blurFFTAct);
    blurFFTMenu->addAction(gaussBlurFFTAct);

    sharpenFFTMenu = new QMenu(tr("&Sharpen"), this);
    sharpenFFTMenu->addAction(sharpenFFTAct);

    edgeDetectFFTMenu = new QMenu(tr("&Detect Edges"), this);
    edgeDetectFFTMenu->addAction(edgeDetectFFTAct);
    edgeDetectFFTMenu->addAction(embossFFTAct);

    filtersMenu = new QMenu(tr("&Filters"), this);
    filtersMenu->setToolTip(tr("Conventional Filters"));
    filtersMenu->addMenu(blurMenu);
    filtersMenu->addMenu(sharpenMenu);
    filtersMenu->addMenu(edgeDetectMenu);
    filtersMenu->addAction(customConvolutionAct);

    FFTMenu = new QMenu(tr("&FFT Filter"), this);
    FFTMenu->setToolTip(tr("Fast Fourier Transform Filters"));
    FFTMenu->addMenu(blurFFTMenu);
    FFTMenu->addMenu(sharpenFFTMenu);
    FFTMenu->addMenu(edgeDetectFFTMenu);

    transformMenu = new QMenu(tr("&Transform"), this);
    transformMenu->addAction(negativeAct);
    transformMenu->addAction(toGrayscaleAct);
    transformMenu->addAction(histogramStretchAct);
    transformMenu->addAction(histogramHSIStretchAct);
    transformMenu->addAction(histogramEquAct);
    transformMenu->addAction(histogramHSIEquAct);

    helpMenu = new QMenu(tr("&Help"), this);
    helpMenu->addAction(aboutAct);
    helpMenu->addAction(aboutQtAct);

    menuBar()->addMenu(fileMenu);
    menuBar()->addMenu(editMenu);
    menuBar()->addMenu(viewMenu);
    menuBar()->addMenu(filtersMenu);
    menuBar()->addMenu(FFTMenu);
    menuBar()->addMenu(transformMenu);
    menuBar()->addMenu(helpMenu);
}

void MainWindow::createStatusBar()
{
    sB = statusBar();

    zoomSB = new QLabel(sB);
    zoomSB->setMinimumSize(zoomSB->sizeHint());
    zoomSB->setToolTip(QString("current zoom level of the image"));
    sB->addPermanentWidget(zoomSB);

    coordSB = new QLabel(sB);
    coordSB->setMinimumSize(coordSB->sizeHint());
    coordSB->setToolTip(tr("Shows the pixel coordinates under the cursor"));
    sB->addPermanentWidget(coordSB);

    sB->showMessage(tr("Ready"));
}

void MainWindow::createDockWidgets()
{
    /**************************************************************************
     Histogram dock widget
     **************************************************************************/
    histogramDock = new HistogramWidget(this);
    addDockWidget(Qt::LeftDockWidgetArea, histogramDock);
    histogramDock->setAllowedAreas(Qt::AllDockWidgetAreas);
    //Enable toggle view action in view Menu
    viewMenu->addAction(histogramDock->toggleViewAction());
    histogramDock->setToolTip(tr("Shows the histogram of the current image"));

    /**************************************************************************
     Pixel information dock widget
     **************************************************************************/
    QDockWidget *pixelInfoDock = new QDockWidget(tr("Pixel information"), this);
    pixelInfoDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
    QScrollArea *scrollArea = new QScrollArea(pixelInfoDock);
    QFrame *frame = new QFrame(scrollArea);
    QGroupBox *coordBox = new QGroupBox(tr("Coordinates"), frame);
    QGroupBox *rgbBox = new QGroupBox(tr("RGB Values"), frame);
    QGroupBox *yuvBox = new QGroupBox(tr("YUV Values"), frame);
    QVBoxLayout *mainLayout = new QVBoxLayout(frame);
    QGridLayout *coordLayout = new QGridLayout(coordBox);
    QGridLayout *rgbLayout = new QGridLayout(rgbBox);
    QGridLayout *yuvLayout = new QGridLayout(yuvBox);

    //add widgets to layouts
    //Coordinates frame
    coordLayout->addWidget(new QLabel(tr("X:")), 1, 0);
    xl = new QLabel();
    coordLayout->addWidget(xl, 1, 1);
    coordLayout->addWidget(new QLabel(tr("Y:")), 2, 0);
    yl = new QLabel();
    coordLayout->addWidget(yl, 2, 1);

    //RGB Value frame
    rgbLayout->addWidget(new QLabel(tr("R:")), 1, 1);
    lR = new QLabel();
    rgbLayout->addWidget(lR, 1, 2);
    rgbLayout->addWidget(new QLabel(tr("G:")), 2, 1);
    lG = new QLabel();
    rgbLayout->addWidget(lG, 2, 2);
    rgbLayout->addWidget(new QLabel(tr("B:")), 3, 1);
    lB = new QLabel();
    rgbLayout->addWidget(lB, 3, 2);

    //YUV Value frame
    yuvLayout->addWidget(new QLabel(tr("Y:")), 1, 1);
    lY = new QLabel();
    yuvLayout->addWidget(lY, 1, 2);
    yuvLayout->addWidget(new QLabel(tr("U:")), 2, 1);
    lU = new QLabel();
    yuvLayout->addWidget(lU, 2, 2);
    yuvLayout->addWidget(new QLabel(tr("V:")), 3, 1);
    lV = new QLabel();
    yuvLayout->addWidget(lV, 3, 2);

    coordBox->setLayout(coordLayout);
    rgbBox->setLayout(rgbLayout);
    yuvBox->setLayout(yuvLayout);

    mainLayout->addWidget(coordBox);
    mainLayout->addWidget(rgbBox);
    mainLayout->addWidget(yuvBox);

    //Add a spacer to keep it clean when resized
    QSpacerItem *vSpacer = new QSpacerItem(0, 0, QSizePolicy::Expanding,
                                           QSizePolicy::Expanding);
    mainLayout->addSpacerItem(vSpacer);
    mainLayout->setSizeConstraint(QLayout::SetFixedSize);

    //Set main Frame layout
    frame->setLayout(mainLayout);
    scrollArea->setWidget(frame);
    scrollArea->setToolTip(tr("Shows information about the pixel when you click on a picture"));

    //Set dock widget and we're done!
    pixelInfoDock->setWidget(scrollArea);
    pixelInfoDock->updateGeometry();
    pixelInfoDock->setToolTip(tr("Click on a pixel of the image to see its information"));
    addDockWidget(Qt::LeftDockWidgetArea, pixelInfoDock);
    //Enable toggle view action in view Menu
    viewMenu->addAction(pixelInfoDock->toggleViewAction());
}

void MainWindow::loadFile(const QString &filePath)
{

    if(imageScene->items().size()!=0) {
        MainWindow *n = new MainWindow;
        n->show();
        n->loadFile(filePath);
        n->setAttribute(Qt::WA_DeleteOnClose);
        return;
    }
    QApplication::setOverrideCursor(Qt::WaitCursor);
    image = LImage(filePath);
    histogramDock->setImage(&image);

    QPixmap img = image.getPixmap();
    if (img.isNull()) {
        QApplication::restoreOverrideCursor();
        QMessageBox::warning(this, tr("Luvlena"),
                                 tr("Cannot load %1.").arg(filePath));
        return;
    }

    undoAct->setEnabled(true);
    redoAct->setEnabled(true);
    setCurrentFile(filePath);
    pathName = curFileInfo->absolutePath();

    imagePixmapItem = imageScene->addPixmap(img);
//    imageScene->setSceneRect(imageScene->itemsBoundingRect());
    imageScene->setSceneRect(imagePixmapItem->boundingRect());
    graphicsView->show();

    QApplication::restoreOverrideCursor();

    updateMenuActions(true);

    zoomLevel = 100;
    rotationAngle = 0;
    updateZoomLabel();

    //if image fits, do nothing, else resize to fit.
    if(imagePixmapItem->boundingRect().toRect().size().width()
        > graphicsView->rect().size().width()
        || imagePixmapItem->boundingRect().toRect().size().height()
        > graphicsView->rect().size().height()) {
        fitInWindow();
    }

    setWindowTitle(QString(curFileInfo->fileName()
                           + " (%1x%2) - "
                           + winTitle).arg(img.width()).arg(img.height()));
    statusBar()->showMessage(tr("Opened %1").arg(filePath));
}

bool MainWindow::saveFile(const QString &fileName)
{
    QImageWriter imageWriter(fileName);
    if (!imageWriter.canWrite()) {
        QMessageBox::warning(this, tr("Luvlena Image Editor"),
                                 tr("Unable to write %1: %2")
                                 .arg(fileName)
                                 .arg(imageWriter.errorString()));
        return false;
    }

    QApplication::setOverrideCursor(Qt::WaitCursor);
    imageWriter.write(imagePixmapItem->pixmap().toImage());
    if(rotationAngle != 0) {
        applyRotate().save(fileName);
        rotationAngle = 0;
    }
    else
        imageWriter.write(imagePixmapItem->pixmap().toImage());
    QApplication::restoreOverrideCursor();

    setCurrentFile(fileName);
    statusBar()->showMessage(tr("Saved '%1'").arg(fileName), 2000);

    image = LImage(fileName);
    graphicsView->resetMatrix();
    updateDisplay();

    return true;
}

void MainWindow::setCurrentFile(const QString &filePath)
{
    if(curFileInfo != NULL && curFileInfo->filePath().compare(filePath) != 0)
        curFileInfo->setFile(filePath);
    setWindowFilePath(curFileInfo->absoluteFilePath());

    QSettings settings("LuvlenaSettings", QSettings::IniFormat);
    QStringList files = settings.value("recentFileList").toStringList();
    files.removeAll(filePath);
    files.prepend(filePath);
    while (files.size() > MaxRecentFiles)
        files.removeLast();

    settings.setValue("recentFileList", files);

    foreach (QWidget *widget, QApplication::topLevelWidgets()) {
        MainWindow *mainWin = qobject_cast<MainWindow *>(widget);
        if (mainWin)
            mainWin->updateRecentFileActions();
    }
}

void MainWindow::updateRecentFileActions()
{
    QSettings settings("LuvlenaSettings", QSettings::IniFormat);
    QStringList files = settings.value("recentFileList").toStringList();

    int numRecentFiles = qMin(files.size(), (int)MaxRecentFiles);

    for (int i = 0; i < numRecentFiles; ++i) {
        QString text = tr("&%1 %2").arg(i + 1).arg(QFileInfo(files[i]).fileName());
        recentFileActs[i]->setText(text);
        recentFileActs[i]->setData(files[i]);
        recentFileActs[i]->setVisible(true);
    }
    for (int j = numRecentFiles; j < MaxRecentFiles; ++j)
        recentFileActs[j]->setVisible(false);
}

void MainWindow::updateMenuActions(bool value)
{
    //File
    saveAct->setEnabled(value);
    saveAsAct->setEnabled(value);
    closeAct->setEnabled(value);
    //Edit
    cropAct->setEnabled(value);
    resizeAct->setEnabled(value);
    mergeAct->setEnabled(value);
    intelligentResizeVAct->setEnabled(value);
    intelligentResizeHAct->setEnabled(value);
    intelligentScissorsAct->setEnabled(value);
    rotateCAct->setEnabled(value);
    rotateACAct->setEnabled(value);
    //View
    zoomInAct->setEnabled(value);
    zoomOutAct->setEnabled(value);
    normalSizeAct->setEnabled(value);
    fillWindowAct->setEnabled(value);
    fitInWindowAct->setEnabled(value);
    //Filter
    blurAct->setEnabled(value);
    gaussBlurAct->setEnabled(value);
    sharpenAct->setEnabled(value);
    edgeDetectAct->setEnabled(value);
    sobelAct->setEnabled(value);
    embossAct->setEnabled(value);
    customConvolutionAct->setEnabled(value);
    //FFT
    blurFFTAct->setEnabled(value);
    gaussBlurFFTAct->setEnabled(value);
    sharpenFFTAct->setEnabled(value);
    edgeDetectFFTAct->setEnabled(value);
    sobelFFTAct->setEnabled(value);
    embossFFTAct->setEnabled(value);
    //Transform
    negativeAct->setEnabled(value);
    histogramStretchAct->setEnabled(value);
    histogramHSIStretchAct->setEnabled(value);
    histogramEquAct->setEnabled(value);
    histogramHSIEquAct->setEnabled(value);
    toGrayscaleAct->setEnabled(value);
}

void MainWindow::scaleView(qreal scaleFactor)
{
    Q_ASSERT(imagePixmapItem->pixmap());
    qreal factor = graphicsView->matrix()
                   .scale(scaleFactor, scaleFactor)
                   .mapRect(QRectF(0, 0, 1, 1)).width();

    zoomLevel *= scaleFactor;
    updateZoomLabel();

    if (factor < 0.07) {
        zoomOutAct->setEnabled(false);
        return;
    }
    else if (factor > 100) {
        zoomInAct->setEnabled(false);
        return;
    }
    else {
        zoomInAct->setEnabled(true);
        zoomOutAct->setEnabled(true);
    }
    graphicsView->scale(scaleFactor, scaleFactor);
}

void MainWindow::applyCrop(QRectF cropRect)
{
    statusBar()->showMessage(tr("Applied crop, new size: %1x%2 pos: %3")
                             .arg(cropRect.width())
                             .arg(cropRect.height())
                             .arg(cropRect.x()), 2000);

    QApplication::setOverrideCursor(Qt::WaitCursor);
    image = image.crop(cropRect.topLeft().x(), cropRect.topLeft().y(), cropRect.bottomRight().x(), cropRect.bottomRight().y());
    updateDisplay();
    QApplication::restoreOverrideCursor();
}

void MainWindow::applyMerge(QRectF cropRect)
{
    QApplication::setOverrideCursor(Qt::WaitCursor);
    m_other = m_other.resizeAverage(cropRect.width(), cropRect.height());
    image = image.mergeImages(m_other, m_coef, cropRect.topLeft().x(), cropRect.topLeft().y());
    updateDisplay();
    QApplication::restoreOverrideCursor();

    statusBar()->showMessage(tr("Merged images"), 2000);
}

QImage MainWindow::applyRotate()
{
    if(rotationAngle < 0)
        return image.rotatecounterclock(abs(rotationAngle));
    //if angle > 0
    return image.rotateclock(rotationAngle);
}

void MainWindow::rotate(qreal angle)
{
    rotationAngle += angle;
    rotationAngle %= 360;
    graphicsView->rotate(angle);
}

void MainWindow::updateZoomLabel()
{
    zoomSB->setText(QString("Zoom: %1%").arg(zoomLevel));
}

void MainWindow::updateDisplay()
{
    imagePixmapItem->setPixmap(image.getPixmap());
    histogramDock->setImage(&image);
    imageScene->setSceneRect(imagePixmapItem->boundingRect());
    graphicsView->ensureVisible(imagePixmapItem);
}
